﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "../xos/head.h"
#include "file_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////
    // 

    static file_impl::POOL * pool_ptr = 0;

    ////////////////////////////////////////////////////////////////////////////////////

    file_impl::file_impl()
    {
        memset( m_szFileName, 0, sizeof( m_szFileName ) );
        m_hFile = INVALID_HANDLE_VALUE;
        m_enumType = FILE_TYPE_NONE;
    }

    file_impl::~file_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int file_impl::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    int file_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int file_impl::term()
    {
        int nRet = 0;

        close();

        return nRet;
    }
    //////////////////////////////////////////////////////////////////////////////////
    // 
    // open a file
    // 
    int file_impl::open( const char * lpszFileName, unsigned long ulAccessFlag, unsigned long ulShareMode, unsigned long ulCreateFlag )
    {
        int nRet = 0;

        unsigned long ulFileAccess = 0, ulFileOpen = 0, ulShare = 0;

        // access type

        if( ulAccessFlag & FILE_WRITE )
        {
            ulFileAccess |= GENERIC_WRITE;
            ulFileAccess |= GENERIC_READ;
        }

        if( ulAccessFlag & FILE_READ )
        {
            ulFileAccess |= GENERIC_READ;
        }

        // create type

        if( ulCreateFlag & FILE_CREATE )
        {
            ulFileOpen |= OPEN_ALWAYS;
        }

        if( ulCreateFlag & FILE_OPEN )
        {
            ulFileOpen |= OPEN_EXISTING;
        }

        if( ulCreateFlag & FILE_TRUNC )
        {
            ulFileOpen |= TRUNCATE_EXISTING;
        }

        // 
        // share type
        // 
        if( ulShareMode & SHARE_READ )
        {
            ulShare |= FILE_SHARE_READ;
        }

        if( ulShareMode & SHARE_WRITE )
        {
            ulShare |= FILE_SHARE_WRITE;
        }

        // 
        // use unicode in windows
        // 
        {
            m_hFile = CreateFileA( 
                lpszFileName, 
                ulFileAccess,
                ulShare,
                0,
                ulFileOpen,
                FILE_ATTRIBUTE_NORMAL,
                0 );
        }

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            DWORD dwErr = GetLastError();
            nRet = 1;
        }

        if( 0 == nRet )
        {
            m_enumType = FILE_TYPE_FILE;
        }

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // get file time
    // 
    int file_impl::get_file_time( xos::xos_i64 * lpCreateTime, xos::xos_i64 * lpAccessTime, xos::xos_i64 * lpModifyTime )
    {
        int ret = 0;

        FILETIME fCreateTime, fAccessTime, fModifyTime;

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            return 1;
        }

        if( !GetFileTime( m_hFile, &fCreateTime, &fAccessTime, &fModifyTime ) )
        {
            return 2;
        }

        if( lpCreateTime )
        {
            xos::xos_i64 sz = fCreateTime.dwHighDateTime;
            sz = ( sz << 32 ) | fCreateTime.dwLowDateTime;
            *lpCreateTime = sz;
        }

        if( lpAccessTime )
        {
            xos::xos_i64 sz = fAccessTime.dwHighDateTime;
            sz = ( sz << 32 ) | fAccessTime.dwLowDateTime;
            *lpAccessTime = sz;
        }

        if( lpModifyTime )
        {
            xos::xos_i64 sz = fModifyTime.dwHighDateTime;
            sz = ( sz << 32 ) | fModifyTime.dwLowDateTime;
            *lpModifyTime = sz;
        }

        return ret;
    }

    // 
    // get file or dir name
    // 
    const char * file_impl::get_file_name( char * lpszFileName, int nLen, int * pnLenNeeded )
    {
        int len = ( int )strlen( m_szFileName );

        if( pnLenNeeded )
        {
            *pnLenNeeded = len;
        }

        if( lpszFileName && ( nLen > len ) )
        {
            strcpy_s( lpszFileName, nLen, m_szFileName );
        }

        return m_szFileName;
    }

    // 
    // is file or dir ? 
    // 
    i_file::enumFileType file_impl::get_file_type()
    {
        return m_enumType;
    }

    // 
    // move file pointer to ...
    // 
    int file_impl::set_file_pos( enumFilePos enumFrom, xos_i64 iPos64, xos_i64 * lpSeek64 )
    {
        int nRet = 0;

        LARGE_INTEGER llToMove = { 0 }, llPos = { 0 };
        DWORD dwType = 0;
        llPos.QuadPart = -1;

        if( 0 == nRet )
        {
            switch( enumFrom )
            {
            case FILE_POS_BEGIN:
                {
                    dwType = FILE_BEGIN;
                }
                break;
            case FILE_POS_CUR:
                {
                    dwType = FILE_CURRENT;
                }
                break;
            case FILE_POS_END:
                {
                    dwType = FILE_END;
                }
                break;
            default:
                {
                    nRet = 1;
                }
                break;
            }
        }

        if( 0 == nRet )
        {
            if( INVALID_HANDLE_VALUE == m_hFile )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            llToMove.QuadPart = iPos64;

            if( !SetFilePointerEx( m_hFile, llToMove, &llPos, dwType ) )
            {
                nRet = 1;
            }
        }

        if( lpSeek64 )
        {
            *lpSeek64 = llPos.QuadPart;
        }

        return nRet;
    }

    // 
    // get current file pointer
    // 
    int file_impl::get_file_pos( xos_i64 * lpSize64 )
    {
        int nRet = 0;

        LARGE_INTEGER llToMove = { 0 }, llPos = { 0 };

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            nRet = 1;
        }

        if( lpSize64 )
        {
            *lpSize64 = 0;
        }

        if( 0 == nRet )
        {
            if( !SetFilePointerEx( m_hFile, llToMove, &llPos, FILE_BEGIN ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            if( lpSize64 )
            {
                *lpSize64 = llPos.QuadPart;
            }
        }

        return nRet;
    }

    // 
    // get file size
    // 
    int file_impl::get_file_size( xos_i64 * lpSize64 )
    {
        int nRet = 0;

        LARGE_INTEGER llSize = { 0 };

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            nRet = 1;
        }

        if( lpSize64 )
        {
            *lpSize64 = 0L;
        }

        if( 0 == nRet )
        {
            if( !GetFileSizeEx( m_hFile, &llSize ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            if( lpSize64 )
            {
                *lpSize64 = llSize.QuadPart;
            }
        }

        return nRet;
    }

    // 
    // commit file disk space.
    // 
    int file_impl::commit_file( xos_i64 iPos64 )
    {
        int nRet = 0;

        LARGE_INTEGER ulSize;
        void * pView = 0;
        HANDLE hMap = 0;

        ulSize.QuadPart = ( LONGLONG )iPos64;

        if( 0 == nRet )
        {
            hMap = CreateFileMapping( m_hFile, 0, PAGE_READWRITE, ulSize.HighPart, ulSize.LowPart, 0 );

            if( !hMap )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            pView = MapViewOfFile( hMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 );
        }

        if( pView )
        {
            UnmapViewOfFile( pView );
            pView = 0;
        }

        if( hMap )
        {
            CloseHandle( hMap );
            hMap = 0;
        }

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // write file data
    // 
    // -1 means failed. other , write bytes
    // 
    int file_impl::write( const void * lpBuf, unsigned long ulBufSize )
    {
        int nRet = 0;

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            nRet = -1;
        }

        if( 0 == nRet )
        {
            DWORD dwLen = 0;

            if( WriteFile( m_hFile, lpBuf, ulBufSize, &dwLen, 0 ) )
            {
                nRet = dwLen;
            }
            else
            {
                nRet = -1;
            }
        }

        return nRet;
    }

    // 
    // read file data
    // 
    // -1 means failed. other , read bytes
    //
    int file_impl::read( void * lpBuf, unsigned long ulBufSize )
    {
        int nRet = 0;

        if( INVALID_HANDLE_VALUE == m_hFile )
        {
            nRet = -1;
        }

        if( 0 == nRet )
        {
            DWORD dwLen = 0;

            if( ReadFile( m_hFile, lpBuf, ulBufSize, &dwLen, 0 ) )
            {
                nRet = dwLen;
            }
            else
            {
                nRet = -1;
            }
        }

        return nRet;
    }

    // 
    // close file handle
    //  
    int file_impl::close()
    {
        int nRet = 0;

        memset( m_szFileName, 0, sizeof( m_szFileName ) );
        m_enumType = FILE_TYPE_NONE;

        if( INVALID_HANDLE_VALUE != m_hFile )
        {
            CloseHandle( m_hFile );
            m_hFile = INVALID_HANDLE_VALUE;
        }

        return nRet;
    }
} // xos
